package info.batcloud.fanli.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ctospace.archit.common.pagination.Paging;
import info.batcloud.fanli.core.dto.ArticleDTO;
import info.batcloud.fanli.core.entity.Article;
import info.batcloud.fanli.core.helper.OSSImageHelper;
import info.batcloud.fanli.core.helper.TimeInfoHelper;
import info.batcloud.fanli.core.repository.ArticleRepository;
import info.batcloud.fanli.core.service.ArticleService;
import info.batcloud.fanli.core.service.UserService;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Inject
    private ArticleRepository articleRepository;

    @Inject
    private UserService userService;

    @Override
    public long createArticle(ArticleCreateParam param) {
        Article article = new Article();
        article.setContent(param.getContent());
        article.setCreateTime(new Date());
        article.setPicListJson(JSON.toJSONString(param.getPicList()));
        article.setFitShareTimes(RandomUtils.nextInt(2000, 3000));
        articleRepository.save(article);
        return article.getId();
    }

    @Override
    public void addShareTimes(long itemSelectionId, int times) {
        Article article = articleRepository.findOne(itemSelectionId);
        article.setShareTimes(article.getShareTimes() + times);
        articleRepository.save(article);
    }

    @Override
    public void updateArticle(long id, ArticleUpdateParam param) {
        Article article = articleRepository.findOne(id);
        article.setPicListJson(JSON.toJSONString(param.getPicList()));
        article.setContent(param.getContent());
        articleRepository.save(article);
    }

    @Override
    @Transactional
    public void deleteById(long id) {
        Article article = articleRepository.findOne(id);
        article.setDeleted(true);
        articleRepository.save(article);
    }

    @Override
    public Paging<ArticleDTO> search(SearchParam param) {
        Specification<Article> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            if (StringUtils.isNotEmpty(param.getKeywords())) {
                expressions.add(cb.like(root.get("content"), "%" + param.getKeywords() + "%"));
            }
            expressions.add(cb.equal(root.get("deleted"), false));
            return predicate;
        };
        Sort sort;
        if (param.getSort() != null) {
            switch (param.getSort()) {
                case SHARE_TIMES_DESC:
                    sort = new Sort(Sort.Direction.DESC, "shareTimes");
                    break;
                case ID_DESC:
                    sort = new Sort(Sort.Direction.DESC, "id");
                    break;
                default:
                    sort = new Sort(Sort.Direction.DESC, "id");
            }
        } else {
            sort = new Sort(Sort.Direction.DESC, "id");
        }
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<Article> page = articleRepository.findAll(specification, pageable);
        List<ArticleDTO> dtoList = toDtoList(page.getContent());
        return Paging.of(dtoList, Long.valueOf(page.getTotalElements()).intValue(),
                param.getPage(), param.getPageSize());
    }

    private List<ArticleDTO> toDtoList(List<Article> articleList) {

        List<ArticleDTO> dtoList = new ArrayList<>();
        articleList.forEach(article -> {
            ArticleDTO dto = new ArticleDTO();
            dto.setUserAvatarUrl(userService.determineUserAvatar(null));
            dto.setUserNickname(userService.determineUserNickname(null));
            dto.setId(article.getId());
            dto.setContent(article.getContent());
            dto.setCreateTime(article.getCreateTime());
            dto.setTimeInfo(TimeInfoHelper.shortTimeInfo(article.getCreateTime()));
            int fitTimes = article.getFitShareTimes();
            if(fitTimes == 0) {
                fitTimes = RandomUtils.nextInt(3000, 5000);
            }
            if (article.getShareTimes() < fitTimes) {
                long millis = System.currentTimeMillis() - article.getCreateTime().getTime();
                Long times = fitTimes * millis / (59 * 60 * 1000);
                dto.setShareTimes(times.intValue() > fitTimes ? fitTimes : times.intValue());
            } else {
                dto.setShareTimes(article.getShareTimes());
            }
            dto.setPicList(JSON.parseObject(article.getPicListJson(), new TypeReference<List<String>>() {
            }).stream().map(o -> OSSImageHelper.toLargeUrl(o)).collect(Collectors.toList()));
            dtoList.add(dto);
        });
        return dtoList;
    }

}
